/* Copyright [2023] <gyl> */
#include <memory>
#include <utility>

#include "common/global_context.h"
#include "event/session_event.h"
#include "event/sql_event.h"
#include "sql/stmt/delete_stmt.h"
#include "sql/stmt/drop_table_stmt.h"
#include "sql/stmt/grant_stmt.h"
#include "sql/stmt/insert_stmt.h"
#include "sql/stmt/select_stmt.h"
#include "sql/stmt/stmt.h"
#include "sql/stmt/update_stmt.h"
#include "sql/stmt/use_stmt.h"
#include "sql/stmt/utils.h"
#include "storage/db/db.h"
#include "storage/default/default_handler.h"
#include "sql/identifier/identify_stage.h"
// using namespace common;

RC IdentifyStage::handle_request(SQLStageEvent *sql_event) {
  if (sql_event->flag() == 1) {
    return RC::SUCCESS;
  }
  std::string user = sql_event->session_event()->user();
  sql_event->set_flag_permit();
  RC rc = RC::SUCCESS;
  Stmt *stmt = sql_event->stmt();

  if (nullptr == stmt) {
    sql_event->set_flag_identify();
    return RC::UNIMPLENMENT;
  }
  switch (stmt->type()) {
    case StmtType::USE: {
      UseStmt *use_stmt = static_cast<UseStmt *>(stmt);
      rc = identify_priv(use_stmt, user);
    } break;

    case StmtType::SELECT: {
      SelectStmt *select_stmt = static_cast<SelectStmt *>(stmt);
      rc = identify_priv(select_stmt, user);
    } break;

    case StmtType::UPDATE: {
      UpdateStmt *update_stmt = static_cast<UpdateStmt *>(stmt);
      rc = identify_priv(update_stmt, user);
    } break;

    case StmtType::DELETE: {
      DeleteStmt *delete_stmt = static_cast<DeleteStmt *>(stmt);
      rc = identify_priv(delete_stmt, user);
    } break;

    case StmtType::INSERT: {
      InsertStmt *insert_stmt = static_cast<InsertStmt *>(stmt);
      rc = identify_priv(insert_stmt, user);
    } break;

    case StmtType::GRANT: {
      rc = identify_priv(sql_event);
    } break;

    case StmtType::DROP_TABLE: {
      DropTableStmt *drop_stmt = static_cast<DropTableStmt *>(stmt);
      rc = identify_priv(drop_stmt, user);
    } break;

    default: {
      rc = RC::SUCCESS;
    }
  }
  SqlResult *sql_result = sql_event->session_event()->sql_result();
  sql_result->set_return_code(rc);
  sql_event->set_flag_identify();
  return rc;
}

RC IdentifyStage::identify_priv(UseStmt *use_stmt, const std::string& user) {
  // only root can use this stmt
  if (user != "root") {
    return RC::ACCESS_DENIED;
  }
  return RC::SUCCESS;
}

RC IdentifyStage::identify_priv(SelectStmt *select_stmt,
                                const std::string& user) {
  DefaultHandler &handler = DefaultHandler::get_default();
  Db *db = handler.find_db("manager");

  std::vector<Table *> tables = select_stmt->tables();
  int priv;
  for (const Table *table : tables) {
    get_priv(db, user, table->name(), priv);
    if (priv == -1) {
      return RC::ACCESS_DENIED;
    }
    if (!(priv & 0x1 << SELECT_BIT)) {
      return RC::ACCESS_DENIED;
    }
  }

  return RC::SUCCESS;
}

RC IdentifyStage::identify_priv(InsertStmt *insert_stmt, std::string user) {
  DefaultHandler &handler = DefaultHandler::get_default();
  Db *db = handler.find_db("manager");

  Table *table = insert_stmt->table();
  int priv;
  get_priv(db, user, table->name(), priv);

  return (priv != -1) && (priv & 0x1 << INSERT_BIT) ? RC::SUCCESS
                                                    : RC::ACCESS_DENIED;
}

RC IdentifyStage::identify_priv(DeleteStmt *delete_stmt, std::string user) {
  DefaultHandler &handler = DefaultHandler::get_default();
  Db *db = handler.find_db("manager");

  Table *table = delete_stmt->table();
  int priv;
  get_priv(db, user, table->name(), priv);

  return (priv != -1) && (priv & 0x1 << DELETE_BIT) ? RC::SUCCESS
                                                    : RC::ACCESS_DENIED;
}

RC IdentifyStage::identify_priv(UpdateStmt *update_stmt, std::string user) {
  DefaultHandler &handler = DefaultHandler::get_default();
  Db *db = handler.find_db("manager");

  Table *table = update_stmt->table();
  int priv;
  get_priv(db, user, table->name(), priv);

  return (priv != -1) && (priv & 0x1 << UPDATE_BIT) ? RC::SUCCESS
                                                    : RC::ACCESS_DENIED;
}

RC IdentifyStage::identify_priv(DropTableStmt *drop_stmt, std::string user) {
  DefaultHandler &handler = DefaultHandler::get_default();
  Db *db = handler.find_db("manager");

  int priv;
  get_priv(db, user, drop_stmt->table_name(), priv);
  return (priv != -1) && (priv & 0x1 << DROP_BIT) ? RC::SUCCESS
                                                  : RC::ACCESS_DENIED;
}

RC IdentifyStage::identify_priv(SQLStageEvent *sql_event) {
  GrantStmt *grant_stmt = static_cast<GrantStmt *>(sql_event->stmt());
  DefaultHandler &handler = DefaultHandler::get_default();
  Db *db = handler.find_db("manager");
  Table *default_table = db->find_table("users");
  if (default_table == nullptr) {
    return RC::SCHEMA_TABLE_NOT_EXIST;
  }

  // 检查被授权的用户是否存在
  std::vector<std::string> users = grant_stmt->users();
  std::vector<std::string> relations = grant_stmt->table_names();
  std::vector<std::string> exists_users;
  get_all_users(db, exists_users);
  std::string user = sql_event->session_event()->user();
  int **operation = new int *[users.size()];
  // 先user后relation，注意这个顺序
  for (int i = 0; i < users.size(); i++) {
    operation[i] = new int[relations.size()];
  }
  for (int i = 0; i < users.size(); i++) {
    if (std::find(exists_users.begin(), exists_users.end(), users[i]) ==
        exists_users.end()) {
      return RC::RECORD_NOT_EXIST;
    }
    // 检查用户是否有权限授权这个表给别人
    // 同时确认user-relation这条记录是否在tables_priv表中存在，若存在则是update操作，对应operation为1，否则为insert操作，对应operation为0
    for (int j = 0; j < relations.size(); j++) {
      int priv;
      int exists;
      get_priv(db, user, relations[j], priv);
      get_priv(db, users[i], relations[j], exists);
      if (exists == -1) {
        operation[i][j] = 0;
      } else {
        operation[i][j] = 1;
      }
      if (((priv >> 5) & 1) != 1 ||
          priv == -1) {  // 第六位代表是否有权授权该表的权限给其他用户
        return RC::ACCESS_DENIED;
      }
    }
  }
  grant_stmt->set_operation(operation);
  return RC::SUCCESS;
}

RC IdentifyStage::get_all_users(Db *db, std::vector<std::string> &users) {
  RC rc = RC::SUCCESS;
  Utils utils;
  std::vector<RelAttrSqlNode> attr;
  RelAttrSqlNode rel;
  rel.attribute_name = "user";
  attr.emplace_back(rel);
  std::vector<RelationSqlNode> relation;
  RelationSqlNode rel_sql;
  rel_sql.relation_name = "users";
  relation.emplace_back(rel_sql);
  Stmt *select_stmt;
  SelectSqlNode select;
  select.attributes = attr;
  select.relations = relation;
  rc = SelectStmt::create(db, select, select_stmt);
  if (rc != RC::SUCCESS) {
    return rc;
  }
  std::vector<Value> values;
  bool flag = false;
  rc = utils.get_value(select_stmt, values, db, flag);
  if (rc != RC::SUCCESS) {
    return rc;
  }
  for (int i = 0; i < values.size(); i++) {
    users.emplace_back(values[i].get_string());
  }
  return rc;
}

RC IdentifyStage::get_priv(Db *db, std::string user, std::string table_name,
                           int &priv) {
  RC rc = RC::SUCCESS;
  Utils utils;
  std::string sql = "select priv from tables_priv where user = '" + user +
                    "' and table_name = '" + table_name + "'";
  ParsedSqlResult parsed_sql_result;
  parse(sql.c_str(), &parsed_sql_result);
  std::unique_ptr<ParsedSqlNode> sql_node =
      std::move(parsed_sql_result.sql_nodes().front());
  Stmt *select_stmt;
  SelectSqlNode select = sql_node->selection;
  rc = SelectStmt::create(db, select, select_stmt);
  if (rc != RC::SUCCESS) {
    return rc;
  }
  std::vector<Value> values;
  bool flag = false;
  rc = utils.get_value(select_stmt, values, db, flag);
  if (rc != RC::SUCCESS) {
    return rc;
  }
  if (values.size() != 0) {
    priv = values[0].get_int();
  } else if (values.size() == 0 &&
             table_name !=
                 "*") {  // 如果指定表名查找不到，那么使用通配符"*"再查找一次
    rc = get_priv(db, user, "*", priv);
    if (rc != RC::SUCCESS) {
      return rc;
    }
  } else {
    priv = -1;
  }
  return rc;
}
